# include <GL/glew.h>
# include <GL/wglew.h>
# include <GL/GL.h>

# include "dfxGraphicsDevice_OGL.h"
# include "dfxProgram_OGL.h"
# include "dfxRenderData_OGL.h"
# include "dfxTexture_OGL.h"
# include "dfxFileLog.h"

# if DFX_PLATFORM == DFX_WINDOWS
    # include "dfxWindow_Win32.h"
# endif

namespace DFX
{
    GLenum  GraphicsDevice_OGL::TextureType[TEXTURE_TYPE_MAX];
    GLenum  GraphicsDevice_OGL::TextureWrap[TEXTURE_WRAP_MAX];
    GLenum  GraphicsDevice_OGL::SurfaceFormat[SURFACE_FORMAT_MAX];
    GLenum  GraphicsDevice_OGL::ImageFormat[IMAGE_FORMAT_MAX];
    GLenum  GraphicsDevice_OGL::ShaderType[SHADER_TYPE_MAX];
    GLenum  GraphicsDevice_OGL::VertexElementFormat[VERTEX_ELEMENT_FORMAT_MAX];
    GLenum  GraphicsDevice_OGL::BufferUsage[BUFFER_USAGE_MAX];
    GLenum  GraphicsDevice_OGL::PrimitiveType[PRIMITIVE_TYPE_MAX];
    GLenum  GraphicsDevice_OGL::BlendOption[BLEND_OPTION_COUNT];
    GLenum  GraphicsDevice_OGL::BlendEquation[BLEND_EQUATION_COUNT];
    GLenum  GraphicsDevice_OGL::CompareFunction[COMPARE_FUNCTION_COUNT];
    GLenum  GraphicsDevice_OGL::StencilOption[STENCIL_OPTION_COUNT];
    GLenum  GraphicsDevice_OGL::StencilFace[STENCIL_FACE_COUNT];
    GLenum  GraphicsDevice_OGL::PolygonMode[FILL_MODE_COUNT];

    GraphicsDevice_OGL::GraphicsDevice_OGL()
        : mWindow(NULL), mInitialized(false)
    {
    }

    GraphicsDevice_OGL::~GraphicsDevice_OGL()
    {
        Destroy();
    }

    Window* GraphicsDevice_OGL::GetWindow()
    {
        return mWindow;
    }

    DFXRESULT GraphicsDevice_OGL::Initialize(Window *window)
    {
        window->AddCallback(this);

# if DFX_PLATFORM == DFX_WINDOWS
        WINDOW_PARAMETERS tempParams =
        {
            (UInt32)-1,
            0,
            0,
            10,
            10,
            32,
            24,
            0,
            0,
            0,
            0
        };

        CorePlugin *corePlugin = CorePlugin::GetPtr();
        corePlugin->RegisterWindowClass("DFXTempClass");

        if (DFX_FAILED(corePlugin->WindowCreate("DFXTempWindow", "DFXTempClass", &mWindow)))
        {
            DFX_ERROR( "Unable to create temporary OpenGL window");
            return DFX_INITFAILED;
        }

        if (DFX_FAILED(mWindow->Create(&tempParams)))
        {
            DFX_ERROR( "Unable to create main OpenGL window with params");
            return DFX_INITFAILED;
        }

        PIXELFORMATDESCRIPTOR pfd =
        {
            sizeof(PIXELFORMATDESCRIPTOR),
            1,
            PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,    //Flags
            PFD_TYPE_RGBA,            //The kind of framebuffer. RGBA or palette.
            32,                        //Colordepth of the framebuffer.
            0, 0, 0, 0, 0, 0,
            0,
            0,
            0,
            0, 0, 0, 0,
            24,                        //Number of bits for the depthbuffer
            8,                        //Number of bits for the stencilbuffer
            0,                        //Number of Aux buffers in the framebuffer.
            PFD_MAIN_PLANE,
            0,
            0, 0, 0
        };
        
        HDC hDC = static_cast<Window_Win32*>(mWindow)->GetHDC();
        Int32 pixelFormat = ChoosePixelFormat(hDC, &pfd);

        if (pixelFormat == 0)
        {
            DFX_ERROR("Unable to choose temporary pixel format");
            return DFX_INITFAILED;
        }

        if (!SetPixelFormat(hDC, pixelFormat, &pfd))
        {
            DFX_ERROR("Unable to set temporary pixel format");
            return DFX_INITFAILED;
        }

        HGLRC hRC = wglCreateContext(hDC);
        wglMakeCurrent(hDC, hRC);

        GLenum err = glewInit();

        if (err != GLEW_OK)
        {
            DFX_ERROR("Unable to initialize glew: %s", glewGetErrorString(err));
            return DFX_INITFAILED;
        }

        GLint major, minor;

        glGetIntegerv(GL_MAJOR_VERSION, &major);
        glGetIntegerv(GL_MINOR_VERSION, &minor);

        wglMakeCurrent(NULL, NULL);
        wglDeleteContext(hRC);

        SAFE_DELETE(mWindow);
        corePlugin->UnregisterWindowClass("DFXTempClass");

        const WINDOW_PARAMETERS *params = (mWindow = window)->GetParameters();        
                 
        UInt32 pixelCount = 0;
        pixelFormat = 0;

        Int32 pixelAttribs[] =
        {
            WGL_SUPPORT_OPENGL_ARB, 1,
            WGL_DRAW_TO_WINDOW_ARB, 1,
            WGL_ACCELERATION_ARB,   WGL_FULL_ACCELERATION_ARB,
            WGL_COLOR_BITS_ARB,     params->ColorBits,
            WGL_DEPTH_BITS_ARB,     params->DepthBits,
            WGL_STENCIL_BITS_ARB,   params->StencilBits,
            WGL_DOUBLE_BUFFER_ARB,  GL_TRUE,
            WGL_SAMPLE_BUFFERS_ARB, params->MSAA > 0 ? GL_TRUE : GL_FALSE,
            WGL_SAMPLES_ARB,        params->MSAA,
            WGL_PIXEL_TYPE_ARB,     WGL_TYPE_RGBA_ARB,
            0
        };

        hDC = static_cast<Window_Win32*>(mWindow)->GetHDC();
        wglChoosePixelFormatARB(hDC, &pixelAttribs[0], NULL, 1, &pixelFormat, &pixelCount);

        if (pixelFormat == -1)
        {
            DFX_ERROR( "Unable to find pixel format requested");
            return DFX_INITFAILED;
        }

        if (!SetPixelFormat(hDC, pixelFormat, &pfd))
        {
            DFX_ERROR("Unable to set primary pixel format");
            return DFX_INITFAILED;
        }

        if (major < 3)
        {
            DFX_ERROR( "Device does not support OpenGL 3.x!!"); 
            return DFX_INITFAILED;
        }

        if (major == 3 && minor < 2)
        {
            DFX_ERROR( "Device does not support OpenGL 3.2!!");
            return DFX_INITFAILED;
        }

        GLint attribs[] =
        {
            WGL_CONTEXT_MAJOR_VERSION_ARB, major,
            WGL_CONTEXT_MINOR_VERSION_ARB, minor,
            WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
            WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
# if defined DFX_DEBUG
            | WGL_CONTEXT_DEBUG_BIT_ARB
# endif
            ,0
        };

        hRC = wglCreateContextAttribsARB(hDC, 0, attribs);

        if (!hRC)
        {
            DFX_ERROR( "Could not create OpenGL %d.%d context", major, minor);
            return DFX_INITFAILED;
        }       

        wglMakeCurrent(hDC, hRC);
        static_cast<Window_Win32*>(mWindow)->SetRC(hRC);

        DFX_INFO("OpenGL %d.%d context created", major, minor);

        GLchar *renderer = (GLchar*)glGetString(GL_RENDERER);
        GLchar *vendor = (GLchar*)glGetString(GL_VENDOR);
        GLchar *version = (GLchar*)glGetString(GL_VERSION);
        GLchar *glslVersion = (GLchar*)glGetString(GL_SHADING_LANGUAGE_VERSION);

        DFX_INFO("OpenGL Vendor:   %s", vendor);
        DFX_INFO("OpenGL Renderer: %s", renderer);
        DFX_INFO("OpenGL Version:  %s", version);
        DFX_INFO("GLSL Version:    %s", glslVersion);
# endif

        glViewport(0, 0, params->Width, params->Height);

        InitializeDefaults();        
        mInitialized = true;

        return DFX_SUCCESS;
    }

    DFXRESULT GraphicsDevice_OGL::CreateAdditional(Window *window)
    {
        if (mInitialized)
        {
# if DFX_PLATFORM == DFX_WINDOWS
            const WINDOW_PARAMETERS *params = window->GetParameters();

            PIXELFORMATDESCRIPTOR pfd =
            {
                sizeof(PIXELFORMATDESCRIPTOR),
                1,
                PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,  
                PFD_TYPE_RGBA,            
                32,                        
                0, 0, 0, 0, 0, 0,
                0,
                0,
                0,
                0, 0, 0, 0,
                24,                       
                8,                       
                0,                       
                PFD_MAIN_PLANE,
                0,
                0, 0, 0
            };

            UInt32 pixelCount = 0;
            Int32 pixelFormat = 0;

            Int32 pixelAttribs[] =
            {
                WGL_SUPPORT_OPENGL_ARB, 1,
                WGL_DRAW_TO_WINDOW_ARB, 1,
                WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
                WGL_COLOR_BITS_ARB, params->ColorBits,
                WGL_DEPTH_BITS_ARB, params->DepthBits,
                WGL_STENCIL_BITS_ARB, params->StencilBits,
                WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
                WGL_SAMPLE_BUFFERS_ARB, params->MSAA > 0 ? GL_TRUE : GL_FALSE,
                WGL_SAMPLES_ARB, params->MSAA,
                WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
                0
            };

            HDC hDC = static_cast<Window_Win32*>(window)->GetHDC();
            wglChoosePixelFormatARB(hDC, &pixelAttribs[0], NULL, 1, &pixelFormat, &pixelCount);

            if (pixelFormat == -1)
            {
                DFX_ERROR("Unable to find pixel format requested");
                return DFX_INITFAILED;
            }

            if (!SetPixelFormat(hDC, pixelFormat, &pfd))
            {
                DFX_ERROR("Unable to set primary pixel format");
                return DFX_INITFAILED;
            }

            HGLRC hRC = static_cast<Window_Win32*>(mWindow)->GetRC();
            static_cast<Window_Win32*>(window)->SetRC(hRC);
# endif
            return DFX_SUCCESS;
        }

        return DFX_CREATEFAILED;
    }

    void GraphicsDevice_OGL::SetCurrent(Window *window)
    {
        if (window)
        {
# if DFX_PLATFORM == DFX_WINDOWS
            Window_Win32 *win32Win = static_cast<Window_Win32*>(window);
            wglMakeCurrent(win32Win->GetHDC(), win32Win->GetRC());
# endif        
        }
    }

    DFXRESULT GraphicsDevice_OGL::Destroy()
    {
        HGLRC hRC = static_cast<Window_Win32*>(mWindow)->GetRC();

        if (hRC)
        {
            wglMakeCurrent(NULL, NULL);
            wglDeleteContext(hRC);

            static_cast<Window_Win32*>(mWindow)->SetRC(NULL);
        }

        return DFX_SUCCESS;
    }

    Texture* GraphicsDevice_OGL::CreateTexture(const String &name, TEXTURE_TYPE type, UInt32 usage, bool mipMaps)
    {
        return new Texture_OGL(name, this, type, usage, mipMaps);
    }

    Program* GraphicsDevice_OGL::CreateProgram(const String &name)
    {
        return new Program_OGL(this, name);
    }

    RenderData* GraphicsDevice_OGL::CreateRenderData(const String &name)
    {
        return new RenderData_OGL(this, name);
    }

    AlphaState* GraphicsDevice_OGL::CreateAlphaState(const AlphaStateDescription &desc)
    {
        return new AlphaState_OGL(this, desc);
    }

    RasterizerState* GraphicsDevice_OGL::CreateRasterizeState(const RasterizerStateDescription &desc)
    {
        return new RasterizerState_OGL(this, desc);
    }

    DepthState* GraphicsDevice_OGL::CreateDepthState(const DepthStateDescription &desc)
    {
        return new DepthState_OGL(this, desc);
    }

    StencilState* GraphicsDevice_OGL::CreateStencilState(const StencilStateDescription &desc)
    {
        return new StencilState_OGL(this, desc);
    }

    void GraphicsDevice_OGL::SetAlphaState(AlphaState *state)
    {
        if (state)
        {
            AlphaState_OGL *alphaState_OGL = static_cast<AlphaState_OGL*>(state);

            if (alphaState_OGL->BlendEnabled != mOldAlphaState->BlendEnabled)
            {
                if (alphaState_OGL->BlendEnabled)
                    glEnable(GL_BLEND);
                else
                    glDisable(GL_BLEND);

                mOldAlphaState->BlendEnabled = alphaState_OGL->BlendEnabled;
            }

            if (alphaState_OGL->AlphaTestEnabled != mOldAlphaState->AlphaTestEnabled)
            {
                if (alphaState_OGL->AlphaTestEnabled)
                    glEnable(GL_ALPHA_TEST);
                else
                    glDisable(GL_ALPHA_TEST);

                mOldAlphaState->AlphaTestEnabled = alphaState_OGL->AlphaTestEnabled;
            }

            if (alphaState_OGL->BlendEnabled)
            {
                if (alphaState_OGL->AlphaFunction != mOldAlphaState->AlphaFunction ||
                    alphaState_OGL->Reference != mOldAlphaState->Reference)
                {
                    glAlphaFunc(alphaState_OGL->AlphaFunction, alphaState_OGL->Reference);
                    mOldAlphaState->AlphaFunction = alphaState_OGL->AlphaFunction;
                    mOldAlphaState->Reference = alphaState_OGL->Reference;
                }

                if (alphaState_OGL->SrcBlend != mOldAlphaState->SrcBlend ||
                    alphaState_OGL->DestBlend != mOldAlphaState->DestBlend)
                {
                    glBlendFunc(alphaState_OGL->SrcBlend, alphaState_OGL->DestBlend);
                    mOldAlphaState->SrcBlend = alphaState_OGL->SrcBlend;
                    mOldAlphaState->DestBlend = alphaState_OGL->DestBlend;
                }

                if (alphaState_OGL->BlendEquation != mOldAlphaState->BlendEquation)
                {
                    glBlendEquation(alphaState_OGL->BlendEquation);
                    mOldAlphaState->BlendEquation = alphaState_OGL->BlendEquation;
                }

                if (alphaState_OGL->ConstantColor[0] != mOldAlphaState->ConstantColor[0] ||
                    alphaState_OGL->ConstantColor[1] != mOldAlphaState->ConstantColor[1] ||
                    alphaState_OGL->ConstantColor[2] != mOldAlphaState->ConstantColor[2] ||
                    alphaState_OGL->ConstantColor[3] != mOldAlphaState->ConstantColor[3])
                {
                    glBlendColor(alphaState_OGL->ConstantColor[0], alphaState_OGL->ConstantColor[1],
                        alphaState_OGL->ConstantColor[2], alphaState_OGL->ConstantColor[3]);

                    memcpy(mOldAlphaState->ConstantColor, alphaState_OGL->ConstantColor,
                        sizeof(GLfloat) * 4);
                }
            }
        }
    }

    void GraphicsDevice_OGL::SetRasterizerState(RasterizerState *state)
    {
        if (state)
        {
            RasterizerState_OGL *rasterizerState_OGL = static_cast<RasterizerState_OGL*>(state);

            if (rasterizerState_OGL->PolygonMode != mOldRasterizerState->PolygonMode)
            {
                glPolygonMode(GL_FRONT_AND_BACK, rasterizerState_OGL->PolygonMode);
                mOldRasterizerState->PolygonMode = rasterizerState_OGL->PolygonMode;
            }

            if (rasterizerState_OGL->Enabled != mOldRasterizerState->Enabled)
            {
                if (rasterizerState_OGL->Enabled)
                {
                    glEnable(GL_CULL_FACE);
                    glCullFace(GL_BACK);                    
                }
                else
                {
                    glDisable(GL_CULL_FACE);
                }

                mOldRasterizerState->Enabled = rasterizerState_OGL->Enabled;
            }
            
            if (rasterizerState_OGL->Enabled)
            {
                if (rasterizerState_OGL->Face != mOldRasterizerState->Face)
                {
                    glFrontFace(rasterizerState_OGL->Face);
                    mOldRasterizerState->Face = rasterizerState_OGL->Face;
                }
            }
        }
    }

    void GraphicsDevice_OGL::SetDepthState(DepthState *state)
    {
        if (state)
        {
            DepthState_OGL *depthState_OGL = static_cast<DepthState_OGL*>(state);

            if (depthState_OGL->Enabled != mOldDepthState->Enabled)
            {
                if (depthState_OGL->Enabled)
                    glEnable(GL_DEPTH_TEST);
                else
                    glDisable(GL_DEPTH_TEST);

                mOldDepthState->Enabled = depthState_OGL->Enabled;
            }

            if (depthState_OGL->Enabled)
            {
                if (depthState_OGL->Writable != mOldDepthState->Writable)
                {
                    glDepthMask(depthState_OGL->Writable);
                    mOldDepthState->Writable = depthState_OGL->Writable;
                }

                if (depthState_OGL->CompareFunction != mOldDepthState->CompareFunction)
                {
                    glDepthFunc(depthState_OGL->CompareFunction);
                    mOldDepthState->CompareFunction = depthState_OGL->CompareFunction;
                }
            }
        }
    }

    void GraphicsDevice_OGL::SetStencilState(StencilState *state)
    {
        if (state)
        {
            StencilState_OGL *stencilState_OGL = static_cast<StencilState_OGL*>(state);

            if (stencilState_OGL->Enabled != mOldStencilState->Enabled)
            {
                if (stencilState_OGL->Enabled)
                    glEnable(GL_STENCIL_TEST);
                else
                    glDisable(GL_STENCIL_TEST);

                mOldStencilState->Enabled = stencilState_OGL->Enabled;
            }

            if (stencilState_OGL->Enabled)
            {    
                if (stencilState_OGL->Face != mOldStencilState->Face ||
                    stencilState_OGL->CompareFunction != mOldStencilState->CompareFunction ||
                    stencilState_OGL->Reference != mOldStencilState->Reference ||
                    stencilState_OGL->Mask != mOldStencilState->Mask)
                {
                    glStencilFuncSeparate(stencilState_OGL->Face, stencilState_OGL->CompareFunction,
                        stencilState_OGL->Reference, stencilState_OGL->Mask);

                    mOldStencilState->CompareFunction = stencilState_OGL->CompareFunction;
                    mOldStencilState->Reference = stencilState_OGL->Reference;
                    mOldStencilState->Mask = stencilState_OGL->Mask;
                }

                if (stencilState_OGL->OnFail != mOldStencilState->OnFail ||
                    stencilState_OGL->OnZFail != mOldStencilState->OnZFail ||
                    stencilState_OGL->OnZPass != mOldStencilState->OnZPass)
                {
                    glStencilOpSeparate(stencilState_OGL->Face, stencilState_OGL->OnFail,
                        stencilState_OGL->OnZFail, stencilState_OGL->OnZPass);

                    mOldStencilState->OnFail = stencilState_OGL->OnFail;
                    mOldStencilState->OnZFail = stencilState_OGL->OnZFail;
                    mOldStencilState->OnZPass = stencilState_OGL->OnZPass;
                }

                if (stencilState_OGL->Face != mOldStencilState->Face)
                {
                    if (stencilState_OGL->Face == GL_FRONT_AND_BACK)
                        glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
                }
            }
        }
    }

    void GraphicsDevice_OGL::SetMaterial(Material *mat)
    {
        if (mat)
        {
            Program *program = mat->GetProgram();

            if (program != NULL && program != mOldProgram)
            {
                program->Bind();   

                for (UInt32 i = 0; i < mat->GetNumTextures(); i++)
                {
                    Texture *texture = mat->GetTexture(i);

                    if (texture != mOldTextures[i])
                        program->SetTexture(mat->GetTextureLoc(i), i, texture);

                    mOldTextures[i] = texture;
                }

                SetAlphaState(mat->GetAlphaState());
                SetRasterizerState(mat->GetRasterizeState());
                SetDepthState(mat->GetDepthState());
                SetStencilState(mat->GetStencilState());

                mOldProgram = program;
            }            
        }
    }

    void GraphicsDevice_OGL::SetRenderData(RenderData *data)
    {
        if (data)
        {
            if (data != mOldRenderData)
            {
                data->Activate();
                mOldRenderData = data;
            }
        }
    }

    void GraphicsDevice_OGL::Clear(UInt32 clearFlags, const Color4 &c, Float32 depth, Int32 stencil)
    {
        UInt32 flags = 0;

        if (clearFlags & CLEAR_FLAGS_TARGET)
        {
            flags |= GL_COLOR_BUFFER_BIT;
            glClearColor(c.R, c.G, c.B, c.A);
        }

        if (clearFlags & CLEAR_FLAGS_DEPTH)
        {
            flags |= GL_DEPTH_BUFFER_BIT;
            glClearDepth(depth);
        }

        if (clearFlags & CLEAR_FLAGS_STENCIL)
        {
            flags |= GL_STENCIL_BUFFER_BIT;
            glClearStencil(stencil);
        }

        glClear(flags);
    }

    void GraphicsDevice_OGL::Present(Window *window)
    {
# if DFX_PLATFORM == DFX_WINDOWS
        Window_Win32 *win32Win = static_cast<Window_Win32*>(window);
        win32Win->SwapBuffers();
# endif
    }

    void GraphicsDevice_OGL::OnCreate(Window *w)
    {
    }

    void GraphicsDevice_OGL::OnDestroy(Window *w)
    {
    }

    void GraphicsDevice_OGL::OnActivate(Window *w)
    {
    }

    void GraphicsDevice_OGL::OnDeactivate(Window *w)
    {
    }

    void GraphicsDevice_OGL::OnResize(Window *w, UInt32 width, UInt32 height)
    {
        if (mInitialized)
            glViewport(0, 0, width, height);
    }

    void GraphicsDevice_OGL::InitializeDefaults()
    {
        TextureType[TEXTURE_TYPE_2D] = GL_TEXTURE_2D;
        TextureType[TEXTURE_TYPE_3D] = GL_TEXTURE_3D;
        TextureType[TEXTURE_TYPE_CUBE] = GL_TEXTURE_CUBE_MAP;

        TextureWrap[TEXTURE_WRAP_REPEAT] = GL_REPEAT;
        TextureWrap[TEXTURE_WRAP_CLAMP] = GL_CLAMP;
        TextureWrap[TEXTURE_WRAP_CLAMPTOEDGE] = GL_CLAMP_TO_EDGE;
        TextureWrap[TEXTURE_WRAP_CLAMPTOBORDER] = GL_CLAMP_TO_BORDER;

        SurfaceFormat[SURFACE_FORMAT_BGR8] = GL_RGB;
        SurfaceFormat[SURFACE_FORMAT_BGRA8] = GL_RGBA;

        ImageFormat[IMAGE_FORMAT_BGR8] = GL_RGB;
        ImageFormat[IMAGE_FORMAT_BGRA8] = GL_RGBA;

        VertexElementFormat[VERTEX_ELEMENT_FORMAT_FLOAT1] = GL_FLOAT;
        VertexElementFormat[VERTEX_ELEMENT_FORMAT_FLOAT2] = GL_FLOAT;
        VertexElementFormat[VERTEX_ELEMENT_FORMAT_FLOAT3] = GL_FLOAT;
        VertexElementFormat[VERTEX_ELEMENT_FORMAT_FLOAT4] = GL_FLOAT;
        VertexElementFormat[VERTEX_ELEMENT_FORMAT_HALF_FLOAT2] = GL_FLOAT;
        VertexElementFormat[VERTEX_ELEMENT_FORMAT_HALF_FLOAT4] = GL_FLOAT;
        VertexElementFormat[VERTEX_ELEMENT_FORMAT_RGBA64] = GL_SHORT;
        VertexElementFormat[VERTEX_ELEMENT_FORMAT_COLOR] = GL_UNSIGNED_BYTE;
        VertexElementFormat[VERTEX_ELEMENT_FORMAT_RGBA32] = GL_SHORT;
        VertexElementFormat[VERTEX_ELEMENT_FORMAT_SHORT2] = GL_SHORT;
        VertexElementFormat[VERTEX_ELEMENT_FORMAT_SHORT4] = GL_SHORT;
        VertexElementFormat[VERTEX_ELEMENT_FORMAT_BYTE4] = GL_UNSIGNED_BYTE;

        BufferUsage[BUFFER_USAGE_STATIC] = GL_STATIC_DRAW;
        BufferUsage[BUFFER_USAGE_DYNAMIC] = GL_DYNAMIC_DRAW;

        PrimitiveType[PRIMITIVE_TYPE_POINT_LIST] = GL_POINTS;
        PrimitiveType[PRIMITIVE_TYPE_LINE_LIST] = GL_LINE;
        PrimitiveType[PRIMITIVE_TYPE_LINE_STRIP] = GL_LINE_STRIP;
        PrimitiveType[PRIMITIVE_TYPE_TRIANGLE_LIST] = GL_TRIANGLES;
        PrimitiveType[PRIMITIVE_TYPE_TRIANGLE_STRIP] = GL_TRIANGLE_STRIP;
        PrimitiveType[PRIMITIVE_TYPE_TRIANGLE_FAN] = GL_TRIANGLE_FAN;

        ShaderType[SHADER_TYPE_VERTEX] = GL_VERTEX_SHADER;
        ShaderType[SHADER_TYPE_GEOMETRY] = GL_GEOMETRY_SHADER;
        ShaderType[SHADER_TYPE_FRAGMENT] = GL_FRAGMENT_SHADER;

        BlendOption[BLEND_OPTION_ZERO] = GL_ZERO;
        BlendOption[BLEND_OPTION_ONE] = GL_ONE;
        BlendOption[BLEND_OPTION_SRC_COLOR] = GL_SRC_COLOR;
        BlendOption[BLEND_OPTION_ONE_MINUS_SRC_COLOR] = GL_ONE_MINUS_SRC_ALPHA;
        BlendOption[BLEND_OPTION_DEST_COLOR] = GL_DST_COLOR;
        BlendOption[BLEND_OPTION_ONE_MINUS_DEST_COLOR] = GL_ONE_MINUS_DST_COLOR;
        BlendOption[BLEND_OPTION_SRC_ALPHA] = GL_SRC_ALPHA;
        BlendOption[BLEND_OPTION_ONE_MINUS_SRC_ALPHA] = GL_ONE_MINUS_SRC_ALPHA;
        BlendOption[BLEND_OPTION_DEST_ALPHA] = GL_DST_ALPHA;
        BlendOption[BLEND_OPTION_ONE_MINUS_DEST_ALPHA] = GL_ONE_MINUS_DST_ALPHA;
        BlendOption[BLEND_OPTION_SRC_ALPHA_SATURATE] = GL_SRC_ALPHA_SATURATE;

        BlendEquation[BLEND_EQUATION_ADD] = GL_FUNC_ADD;
        BlendEquation[BLEND_EQUATION_SUBTRACT] = GL_FUNC_SUBTRACT;
        BlendEquation[BLEND_EQUATION_REV_SUBTRACT] = GL_FUNC_SUBTRACT;
        BlendEquation[BLEND_EQUATION_MIN] = GL_MIN;
        BlendEquation[BLEND_EQUATION_MAX] = GL_MAX;

        CompareFunction[COMPARE_FUNCTION_NEVER] = GL_NEVER;
        CompareFunction[COMPARE_FUNCTION_LESS] = GL_LESS;
        CompareFunction[COMPARE_FUNCTION_LESS_OR_EQUAL] = GL_LEQUAL;
        CompareFunction[COMPARE_FUNCTION_GREATER] = GL_GREATER;
        CompareFunction[COMPARE_FUNCTION_GREATER_OR_EQUAL] = GL_GEQUAL;
        CompareFunction[COMPARE_FUNCTION_EQUAL] = GL_EQUAL;
        CompareFunction[COMPARE_FUNCTION_NOT_EQUAL] = GL_NOTEQUAL;
        CompareFunction[COMPARE_FUNCTION_ALWAYS] = GL_ALWAYS;

        StencilOption[STENCIL_OPTION_KEEP] = GL_KEEP;
        StencilOption[STENCIL_OPTION_ZERO] = GL_ZERO;
        StencilOption[STENCIL_OPTION_REPLACE] = GL_REPLACE;
        StencilOption[STENCIL_OPTION_INCREMENT] = GL_INCR;
        StencilOption[STENCIL_OPTION_DECREMENT] = GL_DECR;
        StencilOption[STENCIL_OPTION_INVERT] = GL_INVERT;
        StencilOption[STENCIL_OPTION_INCREMENT_WRAP] = GL_INCR_WRAP;
        StencilOption[STENCIL_OPTION_DECREMENT_WRAP] = GL_DECR_WRAP;

        StencilFace[STENCIL_FACE_FRONT] = GL_FRONT;
        StencilFace[STENCIL_FACE_BACK] = GL_BACK;
        StencilFace[STENCIL_FACE_FRONT_BACK] = GL_FRONT_AND_BACK;

        PolygonMode[FILL_MODE_POINT] = GL_POINT;
        PolygonMode[FILL_MODE_SOLID] = GL_FILL;
        PolygonMode[FILL_MODE_WIREFRAME] = GL_LINE;
    }
}